/**
 * Copyright (c) 2016-2020 https://github.com/zhaohuatai
 *
 * contact z_huatai@qq.com
 *  
 */

package org.zfes.snowy.auth.shiro.realm;

import java.util.Set;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.zfes.snowy.auth.shiro.event.AuthCacheClearType;
import org.zfes.snowy.auth.shiro.event.AuthChangeEvent;
import org.zfes.snowy.auth.shiro.remote.IRemoteAuthService;

public class AppClientRealm extends SnowyRemoteRealm{
	
    private IRemoteAuthService remoteAuthService;
    
    private String appKey;
	/**
	 *  rpc 加载认证信息
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		AuthenticationInfo authenticationInfo= remoteDoGetAuthenticationInfo(appKey,token);
		return authenticationInfo;
	}
	/**
	 * rpc 加载授权信息，本地缓存，通过 authorizationVersion 升级本地 授权信息缓存
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		AuthorizationInfo authorizationInfo= remoteDoGetAuthorizationInfo(appKey, principals);
	   return authorizationInfo;
	}
	
	@Override
	public AuthenticationInfo remoteDoGetAuthenticationInfo(String appKey, AuthenticationToken authcToken) {
		return remoteAuthService.doGetRemoteAuthenticationInfo(appKey, authcToken);
	}
	@Override
	public AuthorizationInfo remoteDoGetAuthorizationInfo(String appKey, PrincipalCollection principals) {
		return remoteAuthService.doGetRemoteAuthorizationInfo(appKey, principals);
	}
	/**
	 * 清除用户认证信息缓存.通过 authorizationVersion 升级本地 授权信息缓存
	 * @param subject
	 */
	public void clearCachedAuthenticationInfo(Subject subject) {
	   if(subject!=null&&subject.getPrincipals()!=null){
	        super.clearCachedAuthenticationInfo(subject.getPrincipals());
	    }
	}
	/**
	 * 清除用户认证信息缓存.通过 authorizationVersion 升级本地 授权信息缓存
	 * @param subject
	 */
	public void clearAllCachedAuthenticationInfo() {
		Cache<Object, AuthenticationInfo> cache = getAuthenticationCache();
		 if (cache != null&&cache.size()>0) {
	        Set<?> keys=cache.keys();
	            for (Object key : keys) {
	                cache.remove(key);
	            }
	        }
	}
	
	/**
     * 清除用户授权信息缓存.通过 authorizationVersion 升级本地 授权信息缓存
     */
    public void clearCachedAuthorizationInfo(Subject subject) {
    	if(subject!=null&&subject.getPrincipals()!=null){
           super.clearCachedAuthorizationInfo(subject.getPrincipals());
    	}
    }
    
    /**
     * 清除所有用户授权信息缓存.
     */
    public void clearAllCachedAuthorizationInfo() {
        Cache<Object, AuthorizationInfo> cache = getAuthorizationCache();
        if (cache != null&&cache.size()>0) {
        	Set<?> keys=cache.keys();
            for (Object key : keys) {
                cache.remove(key);
            }
        }
    }
	public IRemoteAuthService getRemoteAuthService() {
		return remoteAuthService;
	}
	public void setRemoteAuthService(IRemoteAuthService remoteAuthService) {
		this.remoteAuthService = remoteAuthService;
	}
	public String getAppKey() {
		return appKey;
	}
	public void setAppKey(String clientAppKey) {
		this.appKey = clientAppKey;
	}

    @Async
    @EventListener  
    public void handleAuthChangeEvent(AuthChangeEvent authorEvent) { 
    	AuthCacheClearType cacheClearType=authorEvent.getCacheType();
    	Subject subject=authorEvent.getSubject();
    	switch (cacheClearType) {
		case cachedAuthenticationInfo:
			clearCachedAuthenticationInfo(subject);
			break;
		case allCachedAuthenticationInfo:
			clearAllCachedAuthenticationInfo();
			break;
		case cachedAuthorizationInfoBySubject:
			clearCachedAuthorizationInfo(authorEvent.getSubject());
			break;
		case allCachedAuthorizationInfo:
			clearAllCachedAuthorizationInfo();
			break;
		case allCache:
			clearAllCachedAuthenticationInfo();
			clearAllCachedAuthorizationInfo();
			break;
		default:
			break;
		}
    }  
}
